package com.yunji.generate.service;

import com.yunji.generate.bean.BeanInfo;
import com.yunji.generate.bean.ColumnInfo;
import com.yunji.generate.bean.FieldInfo;
import com.yunji.generate.bean.TableInfo;
import com.yunji.generate.common.BeanConfig;
import com.yunji.generate.common.ResultMessage;
import com.yunji.generate.util.FreemarkerUtil;
import com.yunji.generate.util.StringUtil;
import com.yunji.generate.util.TypeMappingUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author hushuang
 * @since 2019/09/23
 **/
public class BeanGenerator {

    public static String generate(BeanConfig config) {
        return generate(config, null);
    }

    public static String generate(BeanConfig config, IProcessCallback<BeanInfo> callback) {
        String packageDirectory = StringUtil.packageNameToDirectory(config.getPackageName());
        Map<String, Object> contextMap = new HashMap<>(1);
        List<BeanInfo> beans = create(config);

        if (callback != null) {
            callback.onProcessBegin(new IProcessCallback.ListParameter<>(beans));
        }
        int index = 0;
        for (BeanInfo bean : beans) {
            contextMap.clear();
            contextMap.put("bean", bean);

            String fileFullPath = String.format("%s%s%s%s%s.java", config.getSavePath(), File.separator, packageDirectory, File.separator, bean.getName());
            ResultMessage resultMessage = FreemarkerUtil.render("ftl/bean.ftl", contextMap, fileFullPath);
            if (callback != null && callback.onProcessing(new IProcessCallback.Parameter<>(bean, index++, resultMessage))) {
                // 如果 callback 返回 true， 则中断执行
                break;
            }
        }
        if (callback != null) {
            callback.onProcessEnd(new IProcessCallback.ListParameter<>(beans));
        }
        return String.format("%s%s%s", config.getSavePath(), File.separator, packageDirectory);
    }

    private static List<BeanInfo> create(BeanConfig config) {
        List<TableInfo> tables = config.getTables();
        List<BeanInfo> beans = new ArrayList<>(tables.size());
        for (TableInfo table : tables) {
            beans.add(createBean(config, table));
        }
        return beans;
    }

    private static BeanInfo createBean(BeanConfig config, TableInfo table) {
        BeanInfo bean = new BeanInfo();
        bean.setPackageName(config.getPackageName());
        bean.setName(StringUtil.toBeanClassName(table.getName(), config.getTablePrefixes()));
        bean.setTableName(table.getName());
        bean.setRemarks(table.getRemarks());
        bean.setAuthor(config.getAuthor());
        bean.setExcelSupported(table.isExcelSupported());
        bean.setSwaggerSupported(table.isSwaggerSupported());
        bean.setLombokSupported(config.isLombokSupported());
        bean.setFields(table.getColumns().stream().map(BeanGenerator::createField).collect(Collectors.toList()));
        return bean;
    }

    private static FieldInfo createField(ColumnInfo column) {
        FieldInfo field = new FieldInfo();
        field.setClassName(TypeMappingUtil.getJavaType(column));
        field.setRemarks(column.getRemarks());
        field.setTypeName(column.getTypeName());

        field.setName(StringUtil.toCamelCase(column.getColumnName(), false));
        return field;
    }

}
